package com.hm.health.View;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import com.goodix.iot.libbase.logger.Glog;
import com.goodix.utils.DensityUtil;
import com.hm.health.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * Created by chenshi on 2019/12/25.
 */

public class EcgHistoryRecordView extends View {

    public static final String TAG = "ECGChartView";

    private static final int DEFAULT_SIZE = 300;

    private Paint mPaint;
    private Paint mTextPaint;
    private Paint m_gridLinePainter;
    private Paint mLinePaint;

    private int m_gridColor;
    private int m_sGridColor;
    private int m_lineColor;
    private int m_backgroundColor;
    private int mTextColor;
//    private List<Float> mDatas;
    public List<Integer> mDatas = new ArrayList<>();
    public List<Integer> mLeadState = new ArrayList<>();

    private float m_max;
    private float m_min;
    private int m_frequency;
    private float m_sGridWidth;
    private float m_sGridHeight;
    private float mTextSize;
    private float mLineWidth;

    private RectF mEcgChartRect;
    private RectF leftAxisRect;
    private RectF bottomAxisRect;

    private int marginTop;
    private int marginLeft;
    private int marginBottom;
    private int marginRight;

    public static final float DEFAULT_MAX = 2f;
    public static final float DEFAULT_MIN = -1.5f;
    private int mScreenPointCount = 0;
    private int mStartX;
    private GestureDetector mGestureDetector;
    private boolean mEnableDrag;

    IEcgDataListener mEcgDataLister;

    public EcgHistoryRecordView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ECGChartView);
        m_backgroundColor = typedArray.getColor(R.styleable.ECGChartView_back_ground_color, Color.rgb(10,15,20));
        m_gridColor = typedArray.getColor(R.styleable.ECGChartView_grid_line_color, Color.rgb(0x60, 0xE9, 0xAA));
        m_sGridColor = typedArray.getColor(R.styleable.ECGChartView_s_grid_line_color, Color.rgb(0x20, 0x50, 0x3A));
        m_lineColor = typedArray.getColor(R.styleable.ECGChartView_line_color, Color.RED);
        mTextColor = typedArray.getColor(R.styleable.ECGChartView_text_color, Color.BLACK);
        mTextSize = typedArray.getDimension(R.styleable.ECGChartView_text_size, DensityUtil.dip2px(getContext(), 8));
        mLineWidth = typedArray.getDimension(R.styleable.ECGChartView_line_width, DensityUtil.dip2px(getContext(), 2));
        typedArray.recycle();
        init();
    }

    public void setFrequency(int frequency) {
        m_frequency = frequency;
    }

    protected void init() {

        mEcgChartRect = new RectF();
        leftAxisRect = new RectF();
        bottomAxisRect = new RectF();

        m_frequency = 100;
        m_max = DEFAULT_MAX;
        m_min = DEFAULT_MIN;

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setColor(m_backgroundColor);
        mPaint.setStrokeWidth(1);

        mLinePaint = new Paint();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setColor(m_lineColor);
        mLinePaint.setStrokeWidth(mLineWidth);

        m_gridLinePainter = new Paint();
        m_gridLinePainter.setAntiAlias(true);
        m_gridLinePainter.setStyle(Paint.Style.FILL_AND_STROKE);
        m_gridLinePainter.setColor(m_gridColor);
        m_gridLinePainter.setStrokeWidth(1);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mTextSize);

//        mDatas = new ArrayList<>(100 * 500);

        marginTop = DensityUtil.dip2px(getContext(), 4);
        marginLeft = DensityUtil.dip2px(getContext(), 4);
        marginRight = DensityUtil.dip2px(getContext(), 4);
        marginBottom = DensityUtil.dip2px(getContext(), 4);

        mStartX = 0;
        mEnableDrag = false;
        mGestureDetector = new GestureDetector(getContext(), new EcgOnGestureListener());
        m_max = 2f;
        m_min = -1.5f;
    }

    public void setEnableDrag(boolean enableDrag) {
        mEnableDrag = enableDrag;
    }

    public int getScreenPointCount() {
        return mScreenPointCount;
    }

    public void setEcgDataLister(IEcgDataListener lister) {
        mEcgDataLister = lister;
    }

    protected void onDraw(Canvas canvas) {

        int height = getHeight();
        int width =  getWidth();

        float yAxisLabelWidth = DensityUtil.dip2px(getContext(), 24);

        float fontHeight = mTextPaint.descent() - mTextPaint.ascent();
        float xAxisLabelHeight = fontHeight + 2;

        float plotHeight = height - marginBottom - marginTop - xAxisLabelHeight;

        float plotWidth = width - marginLeft - marginRight - yAxisLabelWidth;

        // 左侧Y轴
        leftAxisRect.set(marginLeft, marginTop, yAxisLabelWidth + marginLeft, plotHeight);

        // 曲线块
        mEcgChartRect.set(leftAxisRect.right, leftAxisRect.top, leftAxisRect.right + plotWidth, leftAxisRect.bottom);

        // 底部X轴
        bottomAxisRect.set(leftAxisRect.right, mEcgChartRect.bottom + 1, mEcgChartRect.width(), xAxisLabelHeight);

        // 计算行数
        int rowCount = (int) ((m_max - m_min) / 0.5);
        float gridHeight = mEcgChartRect.height() / rowCount;
        m_sGridHeight = gridHeight / 5f;

        // 计算列数
        float gridWidth = gridHeight;
        int colunmCount = (int)(mEcgChartRect.width() / gridWidth);
        m_sGridWidth = gridWidth / 5f;

        mScreenPointCount = colunmCount * m_frequency / 5;

        drawGrid(canvas, mEcgChartRect);

        drawYAxisScale(canvas, leftAxisRect);

        drawXAxisScale(canvas, bottomAxisRect, colunmCount);

        drawEcgLine(canvas, mEcgChartRect);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int height = getMinHeight(heightMeasureSpec);
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
    }

    private int getMinHeight(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(DEFAULT_SIZE, specSize);
        } else {
            result = DEFAULT_SIZE;
        }
        return result;
    }

    // 获取lead状态
    private int getLeadState(int index, int oldLeadState) {
        int lead = 0;
        if (index < mLeadState.size()) {
            lead = mLeadState.get(index);
        }

        if (lead == 1) {
            // lead on
        } else if (lead == 2) {
            // lead off
        } else {
            // not change
            lead = oldLeadState;
        }

        return lead;
    }

    // 详情页面或实时查看页面绘图根据lead改变颜色
    private void changePainColor(int lead, int index) {
        if (lead == 1) {
            // lead on
            mLinePaint.setColor(m_lineColor);
            Log.d(TAG, "change to color lead on at " + index);
        } else if (lead == 2) {
            // lead off
            mLinePaint.setColor(Color.BLACK);
            Log.d(TAG, "change to color lead off at " + index);
        } else {
            // not change
        }
    }

    private void drawEcgLine(Canvas canvas, RectF plotRect) {

        float xCoef = (float)(plotRect.width() / (mScreenPointCount * 1.0));
        float yZero = m_sGridHeight * m_max * 10 + plotRect.top;

        if (mDatas.size() == 0) {
            return;
        }

        // default lead on
        changePainColor(1, 0);

        // ECG图像滑动窗口绘制，prevLead 表示前一个lead状态
        int prevLead = -1;
        for (int j=mStartX; j>=0; j--) {
            if (j < mLeadState.size()) {
                int lead = mLeadState.get(j);
                if (lead == 1 || lead == 2) {
                    // 1: lead on; 2: lead off
                    prevLead = lead;
                    changePainColor(lead, j);
                    break;
                }
            }
        }

        Path mPath = new Path();
        float v = getDrawData(0) * 10 * m_sGridHeight;
        mPath.moveTo(plotRect.left, yZero - v);

        for (int i = 0; i < mScreenPointCount; ++i) {
            if ((i + mStartX) >= mDatas.size()) {
                break;
            }

            // change color by lead state
            int lead = getLeadState(i + mStartX, prevLead);
            /*if (i==0) {
                Log.d(TAG, "i==0 lead " + lead + ", prev lead " + prevLead);
            }*/

            // change color at lead change
            if (lead != prevLead) {
                canvas.drawPath(mPath, mLinePaint);
                prevLead = lead;
                mPath.reset();
                mPath.moveTo(plotRect.left + i * xCoef, yZero - v);
                changePainColor(lead, i + mStartX);
            }

            v = getDrawData(i + mStartX) * 10 * m_sGridHeight;
            if ((getDrawData(i + mStartX) >= m_max) || (getDrawData(i + mStartX) <= m_min)) {
                Glog.d(TAG, String.format(Locale.ENGLISH,
                        "max, min, curr, %f, %f, %f",
                        m_max, m_min, getDrawData(i)));
            }
            mPath.lineTo(plotRect.left + i * xCoef, 0 - v + yZero);
        }
        canvas.drawPath(mPath, mLinePaint);
    }

    private int dip2px(int dp) {
        return DensityUtil.dip2px(getContext(), dp);
    }

    private float getDrawData(int index) {
        if (index >= mDatas.size())
            return 0;
        float v = mDatas.get(index) / 100f;
        v = v > 2f ? 2f : v;
        v = v < -1.5f ? -1.5f : v;
        return v;
    }
    /**
     * 绘制Y轴以及Y轴坐标
     * @param canvas
     * @param plotRect
     */
    private void drawYAxisScale(Canvas canvas, RectF plotRect) {
        float yZero = m_sGridHeight * m_max * 10 + plotRect.top;
        float x = plotRect.right - dip2px(4);
        Path path = new Path();

        path.moveTo(x, yZero);
        path.lineTo(x - dip2px(4), yZero);
        path.lineTo(x - dip2px(4), yZero - m_sGridHeight * 10);
        path.lineTo(x - dip2px(12), yZero - m_sGridHeight * 10);
        path.lineTo(x - dip2px(12), yZero);
        path.lineTo(x - dip2px(16), yZero);

        int color = mLinePaint.getColor();
        mLinePaint.setColor(Color.DKGRAY);
        canvas.drawPath(path,mLinePaint);
        mLinePaint.setColor(color);
    }

    /**
     * 绘制X轴以及X轴坐标
     * @param canvas
     * @param plotRect
     * @param columnCount
     */
    void drawXAxisScale(Canvas canvas, RectF plotRect, int columnCount) {
        String yLabel = String.format(Locale.ENGLISH, "%.2f", 1.0);
        Rect textRect = new Rect();
        mTextPaint.getTextBounds(yLabel, 0, yLabel.length(), textRect);

        for (int column = 0; column <= columnCount; column += 5) {
            canvas.drawLine(plotRect.left + column * m_sGridWidth * 5 + 1,
                    plotRect.top,
                    plotRect.left + column * m_sGridWidth * 5 + 1,
                    plotRect.top + textRect.height(), mTextPaint);

            String xLab = String.format(Locale.ENGLISH, "  %.1fs",
                    column * 0.2 + mStartX / m_frequency);
            canvas.drawText(xLab,
                    plotRect.left + column * m_sGridWidth * 5,
                    plotRect.top + textRect.height() + 1,
                    mTextPaint);
        }
    }

    private void drawGrid(Canvas canvas, RectF plotRect) {

        m_gridLinePainter.setColor(m_backgroundColor);
        canvas.drawRect(plotRect, m_gridLinePainter);

        int columnCnt = (int)Math.floor(plotRect.width() / m_sGridWidth);
        int rowCount = (int)Math.floor(plotRect.height() / m_sGridHeight);

        float right = plotRect.left + columnCnt * m_sGridWidth;
        float bottom = plotRect.top + rowCount * m_sGridHeight;

        // Draw column
        for (int col = 0; col <= columnCnt; ++col) {
            if (col % 5 == 0) {
                m_gridLinePainter.setStrokeWidth(2);
                m_gridLinePainter.setColor(m_gridColor);
            } else {
                m_gridLinePainter.setColor(m_sGridColor);
                m_gridLinePainter.setStrokeWidth(1);
            }

            float x = plotRect.left + col * m_sGridWidth;

            canvas.drawLine(x, plotRect.top, x,bottom, m_gridLinePainter);
        }

        // Draw row
        for (int row = 0; row <= rowCount; ++row) {
            if (row % 5 == 0) {
                m_gridLinePainter.setStrokeWidth(2);
                m_gridLinePainter.setColor(m_gridColor);
            } else {
                m_gridLinePainter.setColor(m_sGridColor);
                m_gridLinePainter.setStrokeWidth(1);
            }

            float y = plotRect.top + row * m_sGridHeight;
            canvas.drawLine(plotRect.left, y, right, y, m_gridLinePainter);
        }
    }

    public void addPoint(float data) {
        synchronized (mDatas) {
            //mDatas.add(data);
        }
    }

    public void setDatas(List<Integer> data, List<Integer> lead) {
        synchronized (mDatas) {
            mDatas = data;;
            mLeadState = lead;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (mDatas.size() <= mScreenPointCount) {
            return false;
        }

        if (mEnableDrag) {
            mGestureDetector.onTouchEvent(event);
            return true;
        }
        return false;
    }

    public void setYAxisMaxValue(float YAxisMaxValue) {
        m_max = YAxisMaxValue;
    }

    public void setYAxisMinValue(float YAxisMinValue) {
        m_min = YAxisMinValue;
    }

    public void refreshByChooseTime(int progress) {
        mStartX = progress;

        if (mStartX <= 0) {
            // 最左边
            mStartX = 0;
        }

        if (mStartX + mScreenPointCount > mDatas.size()) {
            // 最右边
            mStartX = mDatas.size() - mScreenPointCount;
        }

        invalidate();
    }

    public interface IEcgDataListener {
        void setCurrentProgress(int progress);
    }

    class EcgOnGestureListener implements GestureDetector.OnGestureListener {

        @Override
        public boolean onDown(MotionEvent e) {
            Log.d(TAG, "onDown: ");
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            Log.d(TAG, "onShowPress: ");
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            Log.d(TAG, "onSingleTapUp: ");
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.d(TAG, "onScroll: ");
            if (e1.getX() > mEcgChartRect.left && e1.getX() < mEcgChartRect.right &&
                    e1.getY() > mEcgChartRect.top && e1.getY() < mEcgChartRect.bottom) {

                int p = (int)((distanceX / getWidth()) * mScreenPointCount);

                mStartX += p;

                if (mStartX <= 0) {
                    // 最左边
                    mStartX = 0;
                }

                if (mStartX + mScreenPointCount > mDatas.size()) {
                    // 最右边
                    mStartX = mDatas.size() - mScreenPointCount;
                }

                invalidate();
                if (mEcgDataLister != null) {
                    mEcgDataLister.setCurrentProgress(mStartX);
                }
            }
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    }
}

